﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Threading;
using System.Windows.Forms;
using System.IO;
using System.Windows.Forms.DataVisualization.Charting;

namespace RLGDashboard
{
    public partial class PostMortemView : Form
    {
        private PostMortemDriver postMortemDriver;
        private PostMortemConfig.PostMortemConfigOptions configurationOptions;

        private double InitialAxisValue { get; set; }
        private Axis AxisX { get; set; }
        private LoadScreen loadScreenForm;
        private bool postMortemTerminated;
        Point? prevPosition = null;
        ToolTip tooltip = new ToolTip();

        public PostMortemView(string fileName, LoadScreen form)
        {
            postMortemTerminated = false;
            InitializeComponent();
            configurationOptions = new PostMortemConfig.PostMortemConfigOptions();
            initializeObjects();
            loadScreenForm = form;
            postMortemDriver = new PostMortemDriver(fileName);
            parseFile();
        }

        private void initializeObjects()
        {
            aPostMortemChart.Series["EGT1"].Name = configurationOptions.egtLabels[0];
            aPostMortemChart.Series["EGT2"].Name = configurationOptions.egtLabels[1];
            aPostMortemChart.Series["EGT3"].Name = configurationOptions.egtLabels[2];
            aPostMortemChart.Series["EGT4"].Name = configurationOptions.egtLabels[3];

            aPostMortemChart.Series["PSI1"].Name = configurationOptions.psiLabels[0];
            aPostMortemChart.Series["PSI2"].Name = configurationOptions.psiLabels[1];
            aPostMortemChart.Series["PSI3"].Name = configurationOptions.psiLabels[2];

            aPostMortemChart.Series["RPM1"].Name = configurationOptions.rpmLabels[0];
            aPostMortemChart.Series["RPM2"].Name = configurationOptions.rpmLabels[1];
            aPostMortemChart.Series["RPM3"].Name = configurationOptions.rpmLabels[2];

            aPostMortemChart.Series["AFR"].Name = configurationOptions.afrLabels[0];

            aPostMortemChart.Series["Voltage"].Name = configurationOptions.voltageLabels[0];

            aPostMortemChart.MouseWheel += PostMortemView_MouseWheel;
            aPostMortemChart.MouseMove += PostMortemView_MouseMove;
            aPostMortemChart.EnableZoomAndPanControls();
            aPostMortemChart.ChartAreas[0].AxisX.LabelStyle.Format = "mm:ss";
            aPostMortemChart.ChartAreas[0].AxisY.LabelStyle.Format = "#.##";
            aPostMortemChart.ChartAreas[0].AxisY2.LabelStyle.Format = "#.##";

            aPostMortemChart.Size = this.Size;
            aPostMortemChart.Height = this.Height - 30;
        }

        private void parseFile()
        {
            postMortemDriver.parseFile();
            plotRuns();
        }

        private void plotRuns()
        {
            List<Sensor> plot1DataPoints = new List<Sensor>();
            List<Sensor> plot2DataPoints = new List<Sensor>();

            string[] plot1SeriesNames = null;
            string[] plot2SeriesNames = null;
            plot1SeriesNames = configurationOptions.sensor1Names;
            plot2SeriesNames = configurationOptions.sensor2Names;

            selectPlotType(ref plot1DataPoints, configurationOptions.displayType1, aPostMortemChart.ChartAreas[0].AxisY);
            selectPlotType(ref plot2DataPoints, configurationOptions.displayType2,  aPostMortemChart.ChartAreas[0].AxisY2);

            clearPlot();

            plotDisplayType(plot1DataPoints, plot1SeriesNames, configurationOptions.y1LineColors, System.Windows.Forms.DataVisualization.Charting.AxisType.Primary);
            plotDisplayType(plot2DataPoints, plot2SeriesNames, configurationOptions.y2LineColors, System.Windows.Forms.DataVisualization.Charting.AxisType.Secondary);

            // Set automatic zooming
            aPostMortemChart.ChartAreas[0].AxisX.ScaleView.Zoomable = true;
            aPostMortemChart.ChartAreas[0].AxisX2.ScaleView.Zoomable = true;
            aPostMortemChart.ChartAreas[0].AxisY.ScaleView.Zoomable = true;
            aPostMortemChart.ChartAreas[0].AxisY2.ScaleView.Zoomable = true;

            // Set automatic scrolling 
            aPostMortemChart.ChartAreas[0].CursorX.AutoScroll = true;
            aPostMortemChart.ChartAreas[0].CursorY.AutoScroll = true;

            // Allow user selection for Zoom
            aPostMortemChart.ChartAreas[0].CursorX.IsUserSelectionEnabled = true;
            aPostMortemChart.ChartAreas[0].CursorY.IsUserSelectionEnabled = true;
            aPostMortemChart.ChartAreas[0].CursorX.IsUserEnabled = true;
            aPostMortemChart.ChartAreas[0].CursorY.IsUserEnabled = true;

        }

        private void plotDisplayType(List<Sensor> Datapoints, string[] seriesNames, string[] lineColors, System.Windows.Forms.DataVisualization.Charting.AxisType axisType)
        {
            int index = 0;
            foreach (string series in seriesNames)
            {
                aPostMortemChart.Series[series].IsVisibleInLegend = true;
                aPostMortemChart.Series[series].YAxisType = axisType;
                aPostMortemChart.Series[series].Color = Color.FromName(lineColors[index]);
                plotPoints(series, Datapoints, index);
                index++;
            }
        }

        private void plotPoints(string series, List<Sensor> plotPoints, int index)
        {

            foreach(Sensor tempSensor in plotPoints)
            {
                DateTime timestamp = new DateTime();
                var x = timestamp + tempSensor.timestampMinutes;
                aPostMortemChart.Series[series].Points.AddXY(x, tempSensor.currentSensorValues[index]);
            }
        }

        private void selectPlotType(ref List<Sensor> plot, string displayType,  System.Windows.Forms.DataVisualization.Charting.Axis axis)
        {
            string title = "";
            switch (displayType)
            {
                case "Temperature": plot = postMortemDriver.temperatureList;   
                                    title = "Degrees F"; break;
                case "Pressure": plot = postMortemDriver.pressureList; 
                                 title = "PSI"; break;
                case "AFR": plot = postMortemDriver.afrList; 
                            title = "% 02"; break;
                case "RPM": plot = postMortemDriver.rpmList;
                            title = "RPM"; break;
                case "Voltage": plot = postMortemDriver.voltageList; 
                                title = "Volts"; break;
            }

            axis.Title = title;
        }

        private void clearPlot()
        {
            foreach (string series in configurationOptions.egtLabels)
            {
                aPostMortemChart.Series[series].Points.Clear();
                aPostMortemChart.Series[series].IsVisibleInLegend = false;
            }

            foreach (string series in configurationOptions.voltageLabels)
            {
                aPostMortemChart.Series[series].Points.Clear();
                aPostMortemChart.Series[series].IsVisibleInLegend = false;
            }

            foreach (string series in configurationOptions.afrLabels)
            {
                aPostMortemChart.Series[series].Points.Clear();
                aPostMortemChart.Series[series].IsVisibleInLegend = false;
            }

            foreach (string series in configurationOptions.rpmLabels)
            {
                aPostMortemChart.Series[series].Points.Clear();
                aPostMortemChart.Series[series].IsVisibleInLegend = false;
            }

            foreach (string series in configurationOptions.psiLabels)
            {
                aPostMortemChart.Series[series].Points.Clear();
                aPostMortemChart.Series[series].IsVisibleInLegend = false;
            }
        }

        private void PostMortemView_MouseWheel(object sender, MouseEventArgs e)
        {
            try
            {
                if (e.Delta < 0)
                {
                    aPostMortemChart.ChartAreas[0].AxisX.ScaleView.ZoomReset();
                    aPostMortemChart.ChartAreas[0].AxisY.ScaleView.ZoomReset();
                }

                if (e.Delta > 0)
                {
                    DateTime xMin = DateTime.FromOADate(aPostMortemChart.ChartAreas[0].AxisX.ScaleView.ViewMinimum);
                    DateTime xMax = DateTime.FromOADate(aPostMortemChart.ChartAreas[0].AxisX.ScaleView.ViewMaximum);

                    double y1Min = aPostMortemChart.ChartAreas[0].AxisY.ScaleView.ViewMinimum;
                    double y1Max = aPostMortemChart.ChartAreas[0].AxisY.ScaleView.ViewMaximum;

                    double y2Min = aPostMortemChart.ChartAreas[0].AxisY2.ScaleView.ViewMinimum;
                    double y2Max = aPostMortemChart.ChartAreas[0].AxisY2.ScaleView.ViewMaximum;

                    double yMin, yMax;

                    if (y1Min > y2Min)
                    {
                        yMin = y1Min;
                    }
                    else
                    {
                        yMin = y2Min;
                    }

                    if (y1Max > y2Max)
                    {
                        yMax = y1Max;
                    }
                    else
                    {
                        yMax = y2Max;
                    }

                    double xCursor = aPostMortemChart.ChartAreas[0].AxisX.PixelPositionToValue(e.Location.X);
                    double yCursor = aPostMortemChart.ChartAreas[0].AxisY.PixelPositionToValue(e.Location.Y);

                    DateTime x = DateTime.FromOADate(xCursor);
                    TimeSpan half = xMax - xMin;

                    half = new TimeSpan(half.Ticks / 4);
                    DateTime start = x - half;
                    DateTime end = x + half;
                    double posXStart = (x - half).ToOADate();
                    double posXFinish = (x + half).ToOADate();
                    double posYStart = yCursor - (yMax - yMin) / 4;
                    double posYFinish = yCursor + (yMax - yMin) / 4;

                    aPostMortemChart.ChartAreas[0].AxisX.ScaleView.Zoom(posXStart, posXFinish);
                    aPostMortemChart.ChartAreas[0].AxisY.ScaleView.Zoom(posYStart, posYFinish);
                }
            }
            catch { }
        }
        private void PostMortemView_Resize(object sender, EventArgs e)
        {
            aPostMortemChart.Size = this.Size;
            aPostMortemChart.Height = this.Height - 30;
        }

        private void PostMortemView_FormClosing(object sender, FormClosingEventArgs e)
        {
            if(postMortemTerminated == false)
            {
               loadScreenForm.Close();
            }
            else
            {
                loadScreenForm.Visible = true;
            }
        }

        private void PostMortemView_MouseMove(object sender, MouseEventArgs e)
        {
            var pos = e.Location;
            if (prevPosition.HasValue && pos == prevPosition.Value)
                return;
            tooltip.RemoveAll();
            prevPosition = pos;
            var results = aPostMortemChart.HitTest(pos.X, pos.Y, false,
                                            ChartElementType.DataPoint);

            foreach (var result in results)
            {
                if (result.ChartElementType == ChartElementType.DataPoint)
                {
                    var prop = result.Object as DataPoint;
                    if (prop != null)
                    {
                        var pointXPixel = result.ChartArea.AxisX.ValueToPixelPosition(prop.XValue);
                        var pointYPixel = result.ChartArea.AxisY.ValueToPixelPosition(prop.YValues[0]);
                        var pointY2Pixel = result.ChartArea.AxisY2.ValueToPixelPosition(prop.YValues[0]);

                        // check if the cursor is really close to the point (2 pixels around the point)
                        if (Math.Abs(pos.X - pointXPixel) < 15 &&
                            Math.Abs(pos.Y - pointYPixel) < 15)
                        {
                            string time = getTimeString(DateTime.FromOADate(prop.XValue));
                            tooltip.Show("X=" + time + ", Y1=" + prop.YValues[0], this.aPostMortemChart,
                                            pos.X, pos.Y - 15);
                        }
                        else if( Math.Abs(pos.X - pointXPixel) < 15 &&
                            Math.Abs(pos.Y - pointY2Pixel) < 15)
                        {
                            string time = getTimeString(DateTime.FromOADate(prop.XValue));
                            tooltip.Show("X=" + time + ", Y2=" + prop.YValues[0], this.aPostMortemChart,
                                            pos.X, pos.Y - 15);
                        }
                    }
                }
            }
        }

        private string getTimeString(DateTime x)
        {
            string time = "";

            if (x.Hour < 10)
            {
                time = "0";
            }
                
            time += x.Hour.ToString() + ":";
            
            if (x.Minute < 10)
            {
                time += "0";
            }
            time += x.Minute.ToString() + ":";

            if (x.Second < 10)
            {
                time += "0";
            }

            time += x.Second.ToString() + "." + x.Millisecond.ToString();

            return time;
        }

        private void configurationToolStripMenuItem_Click(object sender, EventArgs e)
        {
            PostMortemConfig configScreen = new PostMortemConfig(ref configurationOptions);

            configScreen.ShowDialog();
            plotRuns();
        }

        private void returnToLoadScreenToolStripMenuItem_Click(object sender, EventArgs e)
        {
            postMortemTerminated = true;
            this.Close();
        }
    }
}
